// 定义配置类的包路径
package com.tsyz.servlet.config;

// 导入所需的拦截器和Spring相关类

import com.tsyz.servlet.interceptor.CorsInterceptor;
import com.tsyz.servlet.interceptor.RequestTimingInterceptor;
import com.tsyz.servlet.interceptor.TsyzTraceIdInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * Spring MVC 的配置类
 * 实现WebMvcConfigurer接口来自定义Spring MVC的配置
 *
 * @author ext.zhaoke14
 */
@Configuration
public class TsyzWebMvcConfig implements WebMvcConfigurer {

    /**
     * 自动注入跨域拦截器实例
     * 用于处理跨域资源共享(CORS)相关的请求
     */
    @Autowired
    private CorsInterceptor corsInterceptor;

    /**
     * 自动注入TraceId拦截器实例
     * 用于生成和传递请求跟踪ID，方便日志追踪和调试
     */
    @Autowired
    private TsyzTraceIdInterceptor traceIdInterceptor;

    /**
     * 自动注入通用日志拦截器实例
     * 用于记录请求处理流程
     */
    @Autowired
    private RequestTimingInterceptor requestTimingInterceptor;

    /**
     * 配置跨域支持的方法
     *
     * @param registry CorsRegistry对象，用于配置跨域规则
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 为API接口配置跨域支持
        registry.addMapping("/api/**")
                // 允许所有来源
                .allowedOriginPatterns("*")
                // 允许所有常见的HTTP方法
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD", "PATCH")
                // 允许所有请求头
                .allowedHeaders("*")
                // 允许携带凭证(cookie等)
                .allowCredentials(true)
                // 预检请求的缓存时间(秒)
                .maxAge(3600);

        // 为其他所有路径配置基础跨域支持
        registry.addMapping("/**").allowedOriginPatterns("*").allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD", "PATCH").allowedHeaders("*").allowCredentials(true).maxAge(3600);
    }

    /**
     * 注册拦截器的方法
     *
     * @param registry InterceptorRegistry对象，用于注册和管理拦截器
     *                 执行顺序很重要：
     *                 1. CorsInterceptor - 首先处理跨域，确保OPTIONS预检请求能正确处理
     *                 2. TsyzTraceIdInterceptor - 生成或传递TraceId，为后续日志记录提供追踪标识
     *                 3. MyInterceptor - 记录请求处理流程
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册跨域拦截器，确保在其他拦截器之前执行
        registry.addInterceptor(corsInterceptor)
                // 拦截所有路径
                .addPathPatterns("/**")
                // 排除静态资源
                .excludePathPatterns("/static/**", "/assets/**", "/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg", "/**/*.gif", "/favicon.ico", "/**/*.html")
                // 优先级最高
                .order(1);

        // 注册traceId拦截器，用于生成和传递请求跟踪ID
        registry.addInterceptor(traceIdInterceptor)
                // 拦截所有路径
                .addPathPatterns("/**")
                // 排除静态资源
                .excludePathPatterns("/static/**", "/assets/**", "/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg", "/**/*.gif", "/favicon.ico", "/**/*.html")
                // 优先级较高
                .order(2);

        // 注册通用日志拦截器
        registry.addInterceptor(requestTimingInterceptor)
                // 拦截所有路径
                .addPathPatterns("/**")
                // 排除静态资源
                .excludePathPatterns("/static/**", "/assets/**", "/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg", "/**/*.gif", "/favicon.ico", "/**/*.html")
                // 优先级中等
                .order(3);
    }

    /**
     * 配置路径匹配，给所有带有@RestController注解且包名包含'controller'的类添加'/api'路径前缀。
     *
     * @param configurer PathMatchConfigurer对象，用于配置路径匹配规则。
     */
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
// 为所有带有@RestController注解且包名包含"controller"的类添加"/api"路径前缀
        configurer.addPathPrefix("/api",
                // 是否存在注释 @RestController
                c -> c.isAnnotationPresent(RestController.class)
                        //  路径是否包含"controller"
                        && c.getPackage().getName().contains("controller"));
    }
}
